#include <stdio.h>
#include "d3d.h"
#include "..\engine\error.h"
#include "..\common\def.h"
#include "..\math\math.h"

//Spacing between lines on the cosole
const int ScreenText::LINE_SPACING = 2; 
//Max number of characters per line
const int ScreenText::NUM_CHARS_LINE = 128; 
//Number of lines that can be rendered on screen at once
const int ScreenText::NUM_TEXT_LINES = 8; 
//Height of characters in pixels
const int ScreenText::TEXT_FONT_HEIGHT = 10; 
//The time allowance for messages to remain before being removed
const float ScreenText::TEXT_CLEAR_TIMER = 10.0f; 

string ScreenText::GetType() const
{
	return string("ScreenText"); 
}


HRESULT ScreenText::Reload()
{
	//TODO:
	return S_OK; 
}


/**************************************
 *
 **************************************/
ScreenText::ScreenText(CD3D9Device* const pDevice) : IResource(pDevice)
{
	m_pFontDefault = NULL; 
	m_pFontBold = NULL; 
	m_OnLine = 0; 
	m_pFlags = NULL; 
	m_pLines = NULL; 
	m_ClearTimer = 0.0f; 
}

/**************************************
 *
 **************************************/
ScreenText::~ScreenText()
{
	Release(); 
}

/**************************************
 *Releases all resources and heap memory
 *associated with this instance
 **************************************/
HRESULT ScreenText::Release()
{
	if(m_pFontDefault)
	{
		m_pFontDefault->Release(); 
		m_pFontDefault = NULL; 
	}

	if(m_pFontBold)
	{
		m_pFontBold->Release(); 
		m_pFontBold = NULL; 
	}

	EE_SAFEDELETEARRAY(m_pLines); 
	EE_SAFEDELETEARRAY(m_pFlags); 
	return S_OK; 
}

/**************************************
 *Initalizies the text object passed in
 *the parameters. It takes care of memory
 *allocations that are required within the
 *text object
 **************************************/
HRESULT CD3D9Device::createTextFont(ScreenText *renderText, const char* fontFace)
{
	if(ISNULL(renderText))
		return E_FAIL; 

	renderText->Release(); 

	if(D3DXCreateFont(m_pD3DDevice, 
		renderText->TEXT_FONT_HEIGHT,
		0,  
		FW_NORMAL, 1, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, 
		(fontFace) ? fontFace : "Small Fonts", &renderText->m_pFontDefault) != D3D_OK)
	{
		CError::CError("D3DXCreateFont failed.", __LINE__, __FILE__); 
		return E_FAIL; 
	}

	if(D3DXCreateFont(m_pD3DDevice, 
		renderText->TEXT_FONT_HEIGHT,
		0,  
		FW_BOLD, 1, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, 
		(fontFace) ? fontFace : "Small Fonts", &renderText->m_pFontBold) != D3D_OK)
	{
		CError::CError("D3DXCreateFont failed.", __LINE__, __FILE__); 
		return E_FAIL; 
	}

	renderText->m_pLines = EE_NEW string [ ScreenText::NUM_TEXT_LINES ]; 
	renderText->m_pFlags = EE_NEW DWORD [ ScreenText::NUM_TEXT_LINES ]; 
	renderText->m_OnLine = 0; 

	for(int i = 0;  i < ScreenText::NUM_TEXT_LINES;  i++)
	{
		renderText->m_pLines[i] = string(); 
		renderText->m_pFlags[i] = 0; 
	}

	return S_OK; 
}

/**************************************
 *Ques a string for onscreen writing. Flags
 *can be found at the top of this file
 **************************************/
void CD3D9Device::WriteLine(string &str, ScreenText::TextFace flags)
{
	m_pDefaultFont->m_ClearTimer = ScreenText::TEXT_CLEAR_TIMER; 

	if(m_pDefaultFont->m_OnLine == ScreenText::NUM_TEXT_LINES)
	{
		//If too many items have been written in this frame, push
		//old ones up to make way for recent entries
		for(int i = 0;  i < ScreenText::NUM_TEXT_LINES - 1;  i++)
		{
			m_pDefaultFont->m_pFlags[i] = m_pDefaultFont->m_pFlags[i + 1]; 
			m_pDefaultFont->m_pLines[i] = m_pDefaultFont->m_pLines[i + 1]; 
		}

		m_pDefaultFont->m_pFlags[ScreenText::NUM_TEXT_LINES - 1] = flags; 
		m_pDefaultFont->m_pLines[ ScreenText::NUM_TEXT_LINES - 1 ].empty(); 
		m_pDefaultFont->m_pLines[ ScreenText::NUM_TEXT_LINES - 1 ] = str; 
	}
	else
	{
		m_pDefaultFont->m_pLines[ m_pDefaultFont->m_OnLine ].empty(); 
		m_pDefaultFont->m_pLines[ m_pDefaultFont->m_OnLine ] = str.c_str(); 

		m_pDefaultFont->m_pFlags[ m_pDefaultFont->m_OnLine ] = flags; 
		m_pDefaultFont->m_OnLine ++; 
	}
}

/**************************************
 *Ques a string for onscreen writing. Flags
 *can be found at the top of this file
 **************************************/
void CD3D9Device::WriteLine(ScreenText::TextFace flags,const char* format,...)
{
	char buffer[ScreenText::NUM_CHARS_LINE] = {(int)' '}; 
	
	va_list	args; 
	va_start (args,format); 
	vsprintf(buffer,format,args); 
	perror(buffer); 
	va_end(args); 

	m_pDefaultFont->m_ClearTimer = ScreenText::TEXT_CLEAR_TIMER; 

	if(m_pDefaultFont->m_OnLine == ScreenText::NUM_TEXT_LINES)
	{
		//If too many items have been written in this frame, push
		//old ones up to make way for recent entries
		for(int i = 0;  i < ScreenText::NUM_TEXT_LINES - 1;  i++)
		{
			m_pDefaultFont->m_pFlags[i] = m_pDefaultFont->m_pFlags[i + 1]; 
			m_pDefaultFont->m_pLines[i] = m_pDefaultFont->m_pLines[i + 1]; 
		}

		m_pDefaultFont->m_pFlags[ScreenText::NUM_TEXT_LINES - 1] = flags; 
		m_pDefaultFont->m_pLines[ ScreenText::NUM_TEXT_LINES - 1 ].empty(); 
		m_pDefaultFont->m_pLines[ ScreenText::NUM_TEXT_LINES - 1 ] = string(buffer); 
	}
	else
	{
		m_pDefaultFont->m_pLines[ m_pDefaultFont->m_OnLine ].empty(); 
		m_pDefaultFont->m_pLines[ m_pDefaultFont->m_OnLine ] = string(buffer); 

		m_pDefaultFont->m_pFlags[ m_pDefaultFont->m_OnLine ] = flags; 
		m_pDefaultFont->m_OnLine ++; 
	}
}

/**************************************
 *The Drawing procedure itterates the
 *character arrays within the text instance
 *and renders them according to their render
 *flags. The strings are cleared each 
 *itteration to allow for 'animation' of
 *strings over many frames
 **************************************/
void CD3D9Device::RenderScreenText(void)
{
	if(m_pDefaultFont->m_OnLine >= 0)
	{
		RECT rect = {0,0,m_deviceSettings.screenWidth,m_pDefaultFont->TEXT_FONT_HEIGHT}; 
		m_pDefaultFont->m_ClearTimer -= 0.1f; 

		if(m_pDefaultFont->m_ClearTimer < 0.0f)
		{
			m_pDefaultFont->m_ClearTimer = m_pDefaultFont->TEXT_CLEAR_TIMER; 
				
			m_pDefaultFont->m_pLines[m_pDefaultFont->m_OnLine].empty(); 
			m_pDefaultFont->m_pFlags[ m_pDefaultFont->m_OnLine ] = 0; 
			m_pDefaultFont->m_OnLine --; 
		}

		for(int i = 0, j = MIN(ScreenText::NUM_TEXT_LINES,m_pDefaultFont->m_OnLine);  i < j;  i++) 
		{
			DWORD flags = m_pDefaultFont->m_pFlags[i]; 
			
			const char* buffer = m_pDefaultFont->m_pLines[i].c_str(); 
			//m_pDefaultFont->m_pLines[i].c_str()
			/*char buffer[ScreenText::NUM_CHARS_LINE] = {0}; 
			strcpy(buffer, m_pDefaultFont->m_pLines[i]); */

			//Switch between different font objects
			if(ScreenText::BOLD_FACE & flags)
			{
				m_pDefaultFont->m_pFontBold->DrawText(NULL,buffer,-1,
					&rect,DT_LEFT | DT_TOP | DT_NOCLIP, 
					(flags & ScreenText::ERROR_FACE) ? 
					D3DCOLOR_XRGB(255,25,25) :
					D3DCOLOR_XRGB(255,255,255)); 			
			}
			else	
			{				
				m_pDefaultFont->m_pFontDefault->DrawText(NULL,buffer,-1,
					&rect,DT_LEFT | DT_TOP | DT_NOCLIP, 
					(flags & ScreenText::ERROR_FACE) ? 
					D3DCOLOR_XRGB(255,25,25) :
					D3DCOLOR_XRGB(255,255,255)); 			
			}

			//Clear this character array to allow it to be updated by the application
			m_pDefaultFont->m_pLines[i].empty(); 
			rect.top += m_pDefaultFont->TEXT_FONT_HEIGHT + m_pDefaultFont->LINE_SPACING; 
		}

		m_pDefaultFont->m_OnLine = 0; 
	}
}
